#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_font.h>

#include <iostream>

#include "Gfx.h"

inline const ALLEGRO_COLOR& ToColor(const Color& col)
{
	return *(ALLEGRO_COLOR*)&col;
}

Pic LoadPic(const char* src)
{
	Pic p = (Pic)al_load_bitmap(src);
	assert(p);
	return p;
}


Pic MakeCircle( float radius, const Color& c )
{
	ALLEGRO_BITMAP* bmp = al_create_bitmap(radius*2, radius*2);
	ALLEGRO_BITMAP* back = al_get_target_bitmap();
	al_set_target_bitmap(bmp);
	ClearScr(Color::Transparent());
	al_draw_filled_circle(radius, radius, radius, ToColor(c));
	al_set_target_bitmap(back);
	return (Pic)bmp;
}

ALLEGRO_BITMAP* screen = 0;

void DrawToPic(Pic pic)
{
	al_set_target_bitmap((ALLEGRO_BITMAP*)pic);
}

Pic MakeRectangle( float w, float h, const Color& c )
{
	ALLEGRO_BITMAP* bmp = al_create_bitmap(w, h);
	ALLEGRO_BITMAP* back = al_get_target_bitmap();
	al_set_target_bitmap(bmp);
	ClearScr(Color::Transparent());
	al_draw_filled_rectangle(0,0,w,h,ToColor(c));
	al_set_target_bitmap(back);
	return (Pic)bmp;
}

void DrawPic(Pic pic, float x, float y)
{
	ALLEGRO_BITMAP* bmp = (ALLEGRO_BITMAP*)pic;
	al_draw_bitmap(bmp, x, y, 0);
}

void DrawPic( Pic pic, float x, float y, float angle, const Color& cl )
{
	ALLEGRO_BITMAP* bmp = (ALLEGRO_BITMAP*)pic;
	al_draw_tinted_rotated_bitmap(bmp, ToColor(cl), PicWidth(pic)/2.0f, PicHeight(pic)/2.0f, x, y, angle, 0);
}

void DrawPic( Pic pic, float x, float y, const Color& cl )
{
	ALLEGRO_BITMAP* bmp = (ALLEGRO_BITMAP*)pic;
	al_draw_tinted_bitmap(bmp, ToColor(cl), x, y, 0);
}

void DrawPicPart( Pic pic, float x, float y, float sx, float sy, float w, float h )
{
	ALLEGRO_BITMAP* bmp = (ALLEGRO_BITMAP*)pic;
	al_draw_bitmap_region(bmp, sx, sy, w, h, x,  y, 0);
}

void DrawPicPart( Pic pic, float x, float y, float sx, float sy, float w, float h, const Color& color, float rotation )
{
	//ALLEGRO_BITMAP* bmp = al_create_sub_bitmap((ALLEGRO_BITMAP*)pic, sx, sy, w, h);
	//al_draw_tinted_bitmap(bmp, ToColor(color), x, y, 0);
	//al_draw_tinted_scaled_rotated_bitmap_region()
	//al_destroy_bitmap(bmp);
	//al_draw_tinted_scaled_rotated_bitmap_region((ALLEGRO_BITMAP*)pic, sx, sy, w, h, ToColor(color), w/2, h/2, x, y, 1.0f, 1.0f, rotation, 0);
}

float PicWidth(Pic pic)
{
	return al_get_bitmap_width((ALLEGRO_BITMAP*)pic);
}

float PicHeight(Pic pic)
{
	return al_get_bitmap_height((ALLEGRO_BITMAP*)pic);
}

void UnloadPic( Pic pic )
{
	if (pic)
		al_destroy_bitmap((ALLEGRO_BITMAP*)pic);
}

Fnt LoadFnt( const char* src, int size )
{
	//ALLEGRO_FONT* fnt = al_load_font(src, -size, 2);
	ALLEGRO_FONT* fnt = al_load_font(src, -size, 0);
	assert(fnt);
	return fnt;
}

void UnloadFnt( Fnt fnt )
{
	al_destroy_font((ALLEGRO_FONT*)fnt);
}

void DrawFnt( Fnt fnt, float x, float y, const Color& cl, const char* format, ... )
{
	char txt[1024];
	va_list ap;
	va_start(ap, format);
	vsprintf(txt, format, ap);
	al_draw_text((ALLEGRO_FONT*)fnt, *(const ALLEGRO_COLOR*)&cl, x, y, 0, txt);
	va_end(ap);
}

void DrawFntBounce( Fnt fnt, float x, float y, const Color& cl, float amplitude, float offset, double faze, const char* format, ... )
{
	char txt[1024];
	va_list ap;
	va_start(ap, format);
	vsprintf(txt, format, ap);
	int w = al_get_text_width((ALLEGRO_FONT*)fnt, txt);
	int len = strlen(txt);
	int l = 0;
	for (int i=0; i<len; i++)
	{
		char letter[2] = {0};
		letter[0] = txt[i];
		al_draw_text((ALLEGRO_FONT*)fnt, *(const ALLEGRO_COLOR*)&cl, x+l, y+sin(faze+offset*i)*amplitude, 0, letter);
		l += al_get_text_width((ALLEGRO_FONT*)fnt, letter);
	}
	va_end(ap);
}

void DrawFntCenter( Fnt fnt, float x, float y, const Color& cl, const char* format, ... )
{
	char txt[1024];
	va_list ap;
	va_start(ap, format);
	vsprintf(txt, format, ap);
	int w = al_get_text_width((ALLEGRO_FONT*)fnt, txt);
	al_draw_text((ALLEGRO_FONT*)fnt, *(const ALLEGRO_COLOR*)&cl, x-w/2, y, 0, txt);
	va_end(ap);
}

void DrawFntCenterBounce( Fnt fnt, float x, float y, const Color& cl, float amplitude, float offset, double faze, const char* format, ... )
{
	char txt[1024];
	va_list ap;
	va_start(ap, format);
	vsprintf(txt, format, ap);
	int w = al_get_text_width((ALLEGRO_FONT*)fnt, txt);
	int len = strlen(txt);
	int l = 0;
	for (int i=0; i<len; i++)
	{
		char letter[2] = {0};
		letter[0] = txt[i];
		al_draw_text((ALLEGRO_FONT*)fnt, *(const ALLEGRO_COLOR*)&cl, (x-w/2)+l, y+sin(faze+offset*i)*amplitude, 0, letter);
		l += al_get_text_width((ALLEGRO_FONT*)fnt, letter);
	}
	va_end(ap);
}


void DrawFntV( Fnt fnt, float x, float y, const Color& cl, const char* format, va_list list )
{
	char txt[1024];
	vsprintf(txt, format, list);
	al_draw_text((ALLEGRO_FONT*)fnt, *(const ALLEGRO_COLOR*)&cl, x, y, 0, txt);
}

float TextLength( Fnt fnt, const char* text )
{
	return al_get_text_width((ALLEGRO_FONT*)fnt, text);
}

float FntHeight( Fnt fnt )
{
	return al_get_font_line_height((ALLEGRO_FONT*)fnt);
}

void Anim::Load( const char* src, int frames, int anims )
{
	Img = LoadPic(src);
	Frames = frames;
	Anims = anims;
	FrameOffset = Vec(PicWidth(Img)/frames, 0);
	AnimOffset = Vec(0, PicHeight(Img)/anims);
}

void Anim::Load( const char* src, Vec framesize )
{
	Img = LoadPic(src);
	Frames = PicWidth(Img)/framesize.X;
	Anims = PicHeight(Img)/framesize.Y;
	FrameOffset = Vec(framesize.X, 0);
	AnimOffset = Vec(0, framesize.Y);
}

void Anim::Unload()
{
	UnloadPic(Img);
}

void Anim::Draw( int anim, int frame, float x, float y )
{
	Vec p = AnimOffset*anim + FrameOffset*frame;
	al_draw_bitmap_region((ALLEGRO_BITMAP*)Img, p.X, p.Y, FrameOffset.X, AnimOffset.Y, x, y, 0);
}

void Anim::Draw( int anim, int frame, float x, float y, const Color& cl )
{
	Vec p = AnimOffset*anim + FrameOffset*frame;
	ALLEGRO_BITMAP* bmp = al_create_sub_bitmap((ALLEGRO_BITMAP*)Img, p.X, p.Y, FrameOffset.X, AnimOffset.Y);
	al_draw_tinted_bitmap(bmp, ToColor(cl), x, y , 0);
	al_destroy_bitmap(bmp);
}
/*

void Anim::Draw( int anim, int frame, float x, float y, float angle )
{

}

void Anim::Draw( int anim, int frame, float x, float y, float angle, const Color& cl )
{

}
*/
void ClearScr(const Color& cl)
{
	al_clear_to_color(*(const ALLEGRO_COLOR*)&cl);
}

void DrawLine( float x1, float y1, float x2, float y2, const Color& cl, float thickness )
{
	al_draw_line(x1,y1,x2,y2,ToColor(cl),thickness);
}

void DrawCircle( float x, float y, float r, const Color& cl, float thickness )
{
	al_draw_circle(x,y,r,ToColor(cl),thickness);
}

void DrawArc( float x, float y, float r, float start, float delta, const Color& cl, float thickness )
{
	al_draw_arc(x, y, r, start, delta, ToColor(cl), thickness);
}

void DrawFilledCircle( float x, float y, float r, const Color& cl )
{
	al_draw_filled_circle(x,y,r,ToColor(cl));
}

void DrawFramedCircle( float x, float y, float r, const Color& clBg, const Color& clFr, float thickness)
{
	al_draw_filled_circle(x,y,r,ToColor(clBg));
  al_draw_circle(x,y,r,ToColor(clFr),thickness);
}

void DrawRect( float x, float y, float w, float h, const Color& cl, float thickness )
{
	al_draw_rectangle(x,y,x+w,y+h,ToColor(cl), thickness);
}

void DrawFilledRect( float x, float y, float w, float h, const Color& cl )
{
	al_draw_filled_rectangle(x,y,x+w,y+h,ToColor(cl));
}

void DrawFramedRect( float x, float y, float w, float h, const Color& clBg, const Color& clFr, float thickness)
{
	al_draw_filled_rectangle(x,y,x+w,y+h,ToColor(clBg));
	al_draw_rectangle(x,y,x+w,y+h,ToColor(clFr), thickness);
}

void DrawQuad( const Vec* pts, Pic pic, const Color& tint /*= Color::White()*/, const Vec* uvs /*= 0*/ )
{
	ALLEGRO_VERTEX vx[4] = {0};
	for (size_t i=0; i<4; i++)
	{
		vx[i].x = pts[i].X;
		vx[i].y = pts[i].Y;
		if (pic)
		{
			if (!uvs)
			{
				vx[i].u = ((i&1)^(i>>1))*PicWidth(pic);
				vx[i].v = (i/2)*PicHeight(pic);
			} else
			{
				vx[i].u = uvs[i].X;
				vx[i].v = uvs[i].Y;
			}
		}
		vx[i].color = ToColor(tint);
	}
	al_draw_prim(vx, 0, (ALLEGRO_BITMAP*)pic, 0, 4, ALLEGRO_PRIM_TRIANGLE_FAN);
}

Pic MakePartPic( Pic pic, float x, float y, float w, float h )
{
	return (Pic)al_create_sub_bitmap((ALLEGRO_BITMAP*)pic, x, y, w, h);
}

void DrawFilledRoundRect( float x, float y, float w, float h, float rx, float ry, const Color& cl )
{
	al_draw_filled_rounded_rectangle(x, y, x+w, y+h, rx, ry, ToColor(cl));
}

void DrawRoundRect(float x, float y, float w, float h, float rx, float ry, const Color& cl, float thickness)
{
	al_draw_rounded_rectangle(x, y, x+w, y+h, rx, ry, ToColor(cl), thickness);
}

void DrawFramedRoundRect(float x, float y, float w, float h, float rx, float ry, const Color& clBg, const Color& clFr, float thickness)
{
	al_draw_rounded_rectangle(x, y, x+w, y+h, rx, ry, ToColor(clFr), thickness);
	al_draw_filled_rounded_rectangle(x, y, x+w, y+h, rx, ry, ToColor(clBg));
}

void DrawSpline(Vec p[4], const Color& cl, float thickness)
{
  float spline[8] = {p[0].X, p[0].Y, p[1].X, p[1].Y, p[2].X, p[2].Y, p[3].X, p[3].Y};
  al_draw_spline(spline, ToColor(cl), thickness);
}